package com.wanfajie.smsdistribute.common.adapter

import android.annotation.SuppressLint
import android.support.v7.widget.RecyclerView
import android.text.Spannable
import android.text.SpannableString
import android.text.style.CharacterStyle
import android.view.ViewGroup
import android.widget.TextView
import com.wanfajie.smsdistribute.util.pinyinInitial
import java.util.*

abstract class SearchRecyclerAdapter<E, VH: RecyclerViewHolder>(
        private val mAdapter: SimpleRecyclerAdapter<E, VH>,
        private val mHighlightFactory: () -> CharacterStyle,
        private val mHighlightIds: Array<Int>
): SimpleRecyclerAdapter<E, VH>() {

    companion object {
        val HIGHLIGHT_INDEX_GENE: (CharSequence, String, Int) -> Pair<Int, Int> = {
            it: CharSequence, kw: String, prevEnd: Int ->

            val index = it.indexOf(kw, prevEnd, ignoreCase = true)
            val end = index + kw.length
            index to end
        }

        val HIGHLIGHT_HANYU_INDEX_GENE: (CharSequence, String, Int) -> Pair<Int, Int> = {
            it, kw, i ->

            if (it.contains(kw, ignoreCase = true)) {
                HIGHLIGHT_INDEX_GENE.invoke(it, kw, i)
            } else {
                val start = it.toString().pinyinInitial.indexOf(kw, i, true)
                start to start + kw.length
            }
        }
    }

    var keyword: String = ""
        private set(value) { field = value }

    override val mItems: MutableList<E> = LinkedList()

    init {
        // XXX: 所有改变都重新过滤太费资源
        mAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {

            override fun onChanged() {
                search()
            }

            override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
                search()
            }

            override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
                search()
            }

            override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
                search()
            }

            override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
                search()
            }
        })
    }

    final override fun getItemCount(): Int {
        return if (keyword.isEmpty()) {
            mAdapter.itemCount
        } else {
            super.getItemCount()
        }
    }

    final override fun getItem(index: Int): E {
        return if (keyword.isEmpty()) {
            mAdapter.getItem(index)
        } else {
            super.getItem(index)
        }
    }

    private fun getRealPos(matchedItemIndex: Int): Int {
        val item = mItems[matchedItemIndex]
        return mAdapter.items.indexOf(item)
    }

    @SuppressLint("MissingSuperCall")
    final override fun onBindViewHolder(p0: VH, p1: Int) {
        if (keyword.isEmpty()) {
            mAdapter.onBindViewHolder(p0, p1)
        } else {
            mAdapter.onBindViewHolder(p0, getRealPos(p1))
            mHighlightIds.forEach {
                val textView = p0.get<TextView>(it)
                textView.text = highlight(textView.text)
            }
        }
    }

    abstract fun filter(index: Int, item: E): Boolean

    override fun onCreateViewHolder(p0: ViewGroup, p1: Int): VH {
        return mAdapter.onCreateViewHolder(p0, p1)
    }

    fun highlight(str: CharSequence, indexGene: (CharSequence, String, Int) -> Pair<Int, Int>): SpannableString {
        val spanStr = SpannableString(str)
        if (keyword.isEmpty()) return spanStr

        var (index, end) = indexGene.invoke(str, keyword, 0)
        while (index != -1) {
            val style = mHighlightFactory.invoke()
            spanStr.setSpan(style, index, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

            val newPos = indexGene.invoke(str, keyword, end)
            index = newPos.first
            end = newPos.second
        }

        return spanStr
    }

    open fun highlight(str: CharSequence): SpannableString {
        return highlight(str, HIGHLIGHT_INDEX_GENE)
    }

    fun search(kw: String) {
        if (kw == keyword) return
        keyword = kw
        search()
    }

    fun search() {
        mItems.clear()
        mAdapter.items.forEachIndexed { i, v ->
            if (filter(i, v)) mItems.add(v)
        }
        notifyDataSetChanged()
    }

    final override fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) {
        super.registerAdapterDataObserver(observer)
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        mAdapter.onAttachedToRecyclerView(recyclerView)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        mAdapter.onDetachedFromRecyclerView(recyclerView)
    }
}